package com.example.prom.qianduoduo.y2025.controller;

import com.alibaba.fastjson.JSON;
import com.example.prom.qianduoduo.y2025.model.SacinfoModel;
import com.example.prom.strategy.excel.CustomCellStyleStrategy;
import com.example.prom.strategy.excel.CustomColumnWidthStrategy;
import com.example.prom.utils.DateUtil;
import com.example.prom.utils.HttpClientSingleton;
import com.example.prom.utils.HttpNewUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.Duration;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.alibaba.excel.EasyExcelFactory.write;

/**
 * Description
 *
 * @author DangWen
 * @date 2025/07/02
 * @since 1.0
 * @version 1.0
 * @website https://dbba.sacinfo.org.cn
 */
@RestController
@RequestMapping("sacinfoSelenium")
public class SacinfoController extends BaseController {

    private static final int TOTAL_PAGES = 785;

    public static void main(String[] args) throws InterruptedException {
        String baseUrl = "https://dbba.sacinfo.org.cn/";
        HttpClient httpClient = HttpClientSingleton.getLongCustomHttpClient();
        long startTime = System.currentTimeMillis();

        List<SacinfoModel> oddResultList = Collections.synchronizedList(new ArrayList<>());
        List<SacinfoModel> evenResultList = Collections.synchronizedList(new ArrayList<>());

        // 线程池执行两个任务
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        // 奇数页任务
        Runnable oddTask = () -> processPages(baseUrl, httpClient, 1, 2, TOTAL_PAGES, oddResultList, startTime, "奇数页线程");
        // 偶数页任务
        Runnable evenTask = () -> processPages(baseUrl, httpClient, 2, 2, TOTAL_PAGES, evenResultList, startTime, "偶数页线程");

        // 提交任务
        executorService.submit(oddTask);
        executorService.submit(evenTask);

        // 等待两个线程完成
        executorService.shutdown();
        executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);

        // 合并结果
        List<SacinfoModel> mergedList = new ArrayList<>();
        mergedList.addAll(oddResultList);
        mergedList.addAll(evenResultList);

        // 去重
        List<SacinfoModel> uniqueList = mergedList.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(SacinfoModel::getPk))),
                        ArrayList::new
                ));

        // 导出到 Excel
        exportExcel(uniqueList);

    }

    /**
     * 处理指定起始页码和步长的页面
     */
    private static void processPages(String baseUrl, HttpClient httpClient, int startPage, int step, int totalPages,
                                     List<SacinfoModel> resultList, Long startTime, String threadName) {
        try {
            Map<String, String> headers = createHeaders();

            WebDriver webDriver = getWebDriver();
            WebDriverWait wait = new WebDriverWait(webDriver, Duration.ofSeconds(30));

            for (int i = startPage; i <= totalPages; i += step) {
                int sleepTime = 500 + new Random().nextInt(500);
                Thread.sleep(sleepTime);
                System.out.println(threadName + " 正在处理第 " + i + " 页");

                List<SacinfoModel> pageData = fetchPageData(httpClient, headers, baseUrl, i, webDriver, wait);
                if (pageData != null) {
                    resultList.addAll(pageData);
                }

                // 进度打印
                double progress = ((double) i / totalPages) * 100;
                System.out.printf("%s 完成总进度：第 %d/%d 页，进度 %.2f%%\n", threadName, i, totalPages, progress);

                // 打印耗时
                long durationMillis = System.currentTimeMillis() - startTime;
                long seconds = TimeUnit.MILLISECONDS.toSeconds(durationMillis) % 60;
                long minutes = TimeUnit.MILLISECONDS.toMinutes(durationMillis) % 60;
                long hours = TimeUnit.MILLISECONDS.toHours(durationMillis);
                System.out.println(threadName+" 总耗时：" + hours + "小时" + minutes + "分钟" + seconds + "秒");
            }

            webDriver.quit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取单页数据
     */
    private static List<SacinfoModel> fetchPageData(HttpClient httpClient, Map<String, String> headers, String baseUrl, int page, WebDriver webDriver, WebDriverWait wait) {
        try {
            Map<String, String> queryMap = new HashMap<>();
            queryMap.put("current", String.valueOf(page));
            queryMap.put("size", "100");
            queryMap.put("status", "现行");

            HttpResponse httpResponse = HttpNewUtils.doPostByApplicationJson(baseUrl + "stdQueryList", null, httpClient, headers, queryMap, JSON.toJSONString(queryMap));
            String result = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
            Map resultMap = (Map) JSON.parse(result);
            Object records = resultMap.get("records");
            List<SacinfoModel> queryResultList = JSON.parseArray(records.toString(), SacinfoModel.class);

            // 转换日期格式、爬取行业分类
            for (SacinfoModel sacinfoModel : queryResultList) {
                processModel(sacinfoModel, webDriver, wait, baseUrl);
            }

            return queryResultList;
        } catch (Exception e) {
            System.err.println("Error fetching page: " + page);
            return Collections.emptyList();
        }
    }

    /**
     * 解析详情页信息
     */
    private static void processModel(SacinfoModel sacinfoModel, WebDriver webDriver, WebDriverWait wait, String baseUrl) throws Exception {
        sacinfoModel.setActDateStr(DateUtil.formatTimeStamp(sacinfoModel.getActDate()));
        sacinfoModel.setIssueDateStr(DateUtil.formatTimeStamp(sacinfoModel.getIssueDate()));
        sacinfoModel.setRecordDateStr(DateUtil.formatTimeStamp(sacinfoModel.getRecordDate()));

        String detailPage = baseUrl + "stdDetail/" + sacinfoModel.getPk();
        webDriver.get(detailPage);
        wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(".main-body")));

        String pageSource = webDriver.getPageSource();
        Document document = Jsoup.parse(pageSource);
        String industryClassification = document.selectFirst("dt:contains(行业分类) + dd").text().trim();
        sacinfoModel.setIndustryClassification(industryClassification);

        Thread.sleep(200 + new Random().nextInt(200));
    }

    /**
     * 导出 Excel
     */
    public static void exportExcel(List<SacinfoModel> resultList) {
        System.out.println("去重前总数量：" + resultList.size());
        List<SacinfoModel> removeDup = resultList.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(SacinfoModel::getPk))),
                        ArrayList::new
                ));
        System.out.println("去重后总数量：" + removeDup.size());

        String fileName = "D:\\workspace-pycharm\\spider-out\\123.xlsx";
        write(fileName, SacinfoModel.class)
                .sheet()
                .head(SacinfoModel.class)
                .registerWriteHandler(new CustomColumnWidthStrategy())
                .registerWriteHandler(new CustomCellStyleStrategy())
                .doWrite(removeDup);
        System.out.println("生成excel成功");
    }


}
